package net.chrone.quickpayapi.controller;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletResponse;

import net.chrone.quickpayapi.api.QrcodeApi;
import net.chrone.quickpayapi.model.Merchant;
import net.chrone.quickpayapi.model.Order;
import net.chrone.quickpayapi.model.PayChannel;
import net.chrone.quickpayapi.model.PlatOrgInf;
import net.chrone.quickpayapi.service.MerchantService;
import net.chrone.quickpayapi.service.OrderService;
import net.chrone.quickpayapi.service.OrgFeeRateService;
import net.chrone.quickpayapi.service.PayChannelService;
import net.chrone.quickpayapi.service.PlatOrgInfService;
import net.chrone.quickpayapi.service.RiskService;
import net.chrone.quickpayapi.util.Constant;
import net.chrone.quickpayapi.util.RegexUtil;
import net.chrone.quickpayapi.util.SdkUtil;
import net.chrone.quickpayapi.util.SignatureUtil;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import com.alibaba.fastjson.JSON;

/**
 * 扫码支付3.0版本 支持多通道路由
 * @author Jerry
 */
@Controller
@RequestMapping("/v4.0/order")
public class OrderV4Controller {

	private final Logger logger = Logger.getLogger(getClass());

	@Autowired
	private PlatOrgInfService platOrgInfService;
	@Autowired
	private MerchantService merchantService;
	@Autowired
	private OrderService orderService;
	@Autowired
	private PayChannelService payChannelService;
	@Autowired
	private RiskService riskService;
	@Autowired
	private OrgFeeRateService orgFeeRateService;

	/**
	 * 二维码支付
	 * 
	 * @param merchant
	 * @param response
	 */
	@Transactional(rollbackFor = Exception.class)
	@RequestMapping(value = "/qrpay", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
	public void qrpay(@RequestBody Order order, HttpServletResponse response) throws Exception {
		logger.debug("order:" + order);
		Map<String, String> respMap = new HashMap<String, String>();
		if (StringUtils.isEmpty(order.getOrgId())) {
			logger.error("机构号不能为空");
			respMap.put("respCode", "401");
			response(respMap, response);
			return;
		}
		PlatOrgInf platOrgInf = platOrgInfService.findById(order.getOrgId());
		if (platOrgInf == null) {
			logger.error("找不到机构信息,orgId:" + order.getOrgId());
			respMap.put("respCode", "402");
			response(respMap, response);
			return;
		}
		boolean flag = SignatureUtil.verify(order.getSignature(), order, platOrgInf.getPublicKey());
		if (!flag) {
			logger.error("验签失败");
			respMap.put("respCode", "403");
			response(respMap, response);
			return;
		}
		if (StringUtils.isEmpty(order.getAccount()) || !RegexUtil.validMobile(order.getAccount())) {
			logger.error("account格式错,account:" + order.getAccount());
			respMap.put("respCode", "404");
			response(respMap, response);
			return;
		}
		if(order.getSettleAmt()>order.getAmount()){
			respMap.put("respCode", "422");
			response(respMap, response);
			return;
		}
		Merchant merchant = merchantService.find(order.getOrgId(), order.getAccount());
		if (merchant == null) {
			logger.error("account不存在,account:" + order.getAccount());
			respMap.put("respCode", "411");
			response(respMap, response);
			return;
		}
		if (Constant.MCHNT_ST_AUDIT_PASS != merchant.getAccountSt()) {
			logger.error("账户状态异常,account:" + merchant.getAccount());
			respMap.put("respCode", "415");
			response(respMap, response);
			return;
		}
		order.setOrderTp(Constant.QRCODE_0);
		PayChannel channel = payChannelService.getChannle(order);// 暂定查找微信的通道
		if (channel==null) {
			respMap.put("respCode", "421");
			response(respMap, response);
			return;
		}
		int feeAmt = orgFeeRateService.caclFee(order);//计算手续费
		if(order.getAmount()<feeAmt){
			respMap.put("respCode", "412");//手续费大于本金
			response(respMap, response);
			return;
		}
		if(order.getSettleAmt()>(order.getAmount()-feeAmt)){
			respMap.put("respCode", "423");//清算金额大于本金减去手续费
			response(respMap, response);
			return;
		}
		order.setFee(feeAmt);
		logger.debug("找到通道代码:"+channel.getCode());
		if(0==channel.getFeeType()){//百分比
			order.setChnlFee(SdkUtil.caclFee(order.getAmount(), channel.getFeeRate()));
		}else{//按笔
			Double fee = 100*channel.getFeeRate();
			order.setChnlFee(fee.intValue());
		}
		order.setPayChannelId(channel.getCode());
		String checkCode = riskService.riskCheck(order);//风控检查
		if(StringUtils.isNotEmpty(checkCode)){
			respMap.put("respCode", checkCode);
			response(respMap, response);
			return;
		}
		
		order.setZxMchntId(SdkUtil.getStringValue("citicMchntId"));
		order = orderService.newOrder(order, merchant);// 入库
		QrcodeApi.getQrcode(order, merchant);// 获取二维码
		if (StringUtils.isNotEmpty(order.getQrcodeUrl())) {// 上游成功
			try {
				orderService.updateByPrimaryKey(order);//更新收款订单
				
				respMap.put("respCode", "200");// 成功
				respMap.put("qrcode", order.getQrcodeUrl());
				response(respMap, response);
				return;
			} catch (Exception e) {
				e.printStackTrace();
				logger.debug("error msg:" + e.getMessage());
				if (e.getMessage().indexOf("Duplicate entry") > 0) {
					respMap.put("respCode", "413");// 订单号重复
				} else {
					respMap.put("respCode", "500");// 系统异常
				}
				response(respMap, response);
				return;
			}
		} else {// 上游失败
			respMap.put("respCode", "414");
			response(respMap, response);
			return;
		}
	}
	

	private void response(Map<String, String> respMap, HttpServletResponse response) {
		respMap.put("respMsg", Constant.getErrorCodeMap().get(respMap.get("respCode")));
		respMap.put("signature", SignatureUtil.signResp(respMap));
		String json = JSON.toJSONString(respMap);
		try {
			response.setCharacterEncoding("utf-8");
			response.getWriter().write(json);
			response.getWriter().flush();
			response.getWriter().close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}
